package org.blame.lotterysystem.service.mq;


import cn.hutool.core.date.DateUtil;
import org.blame.lotterysystem.common.exception.ServiceException;
import org.blame.lotterysystem.common.utils.JacksonUtil;
import org.blame.lotterysystem.common.utils.MailUtil;
import org.blame.lotterysystem.common.utils.SMSUtil;
import org.blame.lotterysystem.controller.param.DrawPrizeParam;
import org.blame.lotterysystem.dao.dataObject.ActivityPrizeDO;
import org.blame.lotterysystem.dao.dataObject.WinningRecordDO;
import org.blame.lotterysystem.dao.mapper.ActivityPrizeMapper;
import org.blame.lotterysystem.dao.mapper.WinningRecordMapper;
import org.blame.lotterysystem.service.DrawPrizeService;
import org.blame.lotterysystem.service.activityStatus.ActivityStatusManager;
import org.blame.lotterysystem.service.dto.ConvertActivityStatusDTO;

import org.blame.lotterysystem.service.enums.ActivityPrizeEnum;
import org.blame.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import org.blame.lotterysystem.service.enums.ActivityStatusEnum;
import org.blame.lotterysystem.service.enums.ActivityUserEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.blame.lotterysystem.common.config.DirectRabbitConfig.QUEUE_NAME;

@Component
@RabbitListener(queues = QUEUE_NAME)
public class MqReceiver {

    @Autowired
    private DrawPrizeService drawPrizeService;

    @Autowired
    private ActivityStatusManager activityStatusManager;

    @Autowired
    private MailUtil mailUtil;

    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;

    @Autowired
    @Qualifier("asyncServiceExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private SMSUtil smsUtil;

    private static final Logger logger= LoggerFactory.getLogger(MqReceiver.class);

    @RabbitHandler
    public void process(Map<String,String> message){
        logger.info("process  message:{}", JacksonUtil.writeValueAsString(message));
        String paramString= message.get("messageData");
        DrawPrizeParam param=JacksonUtil.readValue(paramString, DrawPrizeParam.class);

//      处理抽奖的流程
        try {
            //      校验抽奖请求是否有效
            if (!drawPrizeService.checkDrawPrizeParam(param)){
                return;
            }
            //      状态扭转处理（重要！！ 设计模式
            statusConvert(param);
            //      保存中奖者名单
            List<WinningRecordDO> winningRecordDOS = drawPrizeService.saveWinnerRecords(param);

            //进行邮件，短信的通知
            syncExecute(winningRecordDOS);

        }catch (ServiceException e){

            rollback(param);

        }catch (Exception e){

            rollback(param);

        }
    }

    private void rollback(DrawPrizeParam param) {

        // 1、回滚状态：活动、奖品、人员
        // 状态是否需要回滚
        if (!statusNeedRollback(param)) {
            // 不需要：return
            return;
        }
        // 需要回滚: 回滚
        rollbackStatus(param);

        // 2、回滚中奖者名单
        // 是否需要回滚
        if (!winnerNeedRollback(param)) {
            // 不需要：return
            return;
        }
        // 需要: 回滚
        rollbackWinner(param);

    }

    private boolean statusNeedRollback(DrawPrizeParam param) {
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());
        return activityPrizeDO.getStatus().equalsIgnoreCase(ActivityPrizeEnum.COMPLETED.name());
    }
    private void rollbackStatus(DrawPrizeParam param) {
        ConvertActivityStatusDTO convertActivityStatusDTO = new ConvertActivityStatusDTO();
        convertActivityStatusDTO.setActivityId(param.getActivityId());
        convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.RUNNING);
        convertActivityStatusDTO.setPrizeId(param.getPrizeId());
        convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeEnum.INIT);
        convertActivityStatusDTO.setUserIds(
                param.getWinnerList().stream()
                        .map(DrawPrizeParam.Winner::getUserId)
                        .collect(Collectors.toList())
        );
        convertActivityStatusDTO.setTargetUserStatus(ActivityUserEnum.INIT);
        activityStatusManager.rollbackHandlerEvent(convertActivityStatusDTO);
    }

    private boolean winnerNeedRollback(DrawPrizeParam param) {
        int count = winningRecordMapper.countByAPId(param.getActivityId(), param.getPrizeId());
        return count > 0;
    }

    private void rollbackWinner(DrawPrizeParam param) {
        drawPrizeService.deleteRecords(param.getActivityId(), param.getPrizeId());
    }





    private void syncExecute(List<WinningRecordDO> winningRecordDOS) {

        threadPoolTaskExecutor.execute(()->{sendMessage(winningRecordDOS);});
        threadPoolTaskExecutor.execute(()->{sendEmail(winningRecordDOS);});


    }

    private void sendEmail(List<WinningRecordDO> winningRecordDOS) {
        if(CollectionUtils.isEmpty(winningRecordDOS)){
            logger.info("中奖信息为空，不需要发送邮件");
            return;
        }

        for (WinningRecordDO winningRecordDO:winningRecordDOS){
            String context = "Hi，" + winningRecordDO.getWinnerName() + "。恭喜你在"
                    + winningRecordDO.getActivityName() + "活动中获得"
                    + ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTier()).getMessage()
                    + "：" + winningRecordDO.getPrizeName() + "。获奖时间为"
                    + DateUtil.formatTime(winningRecordDO.getWinningTime()) + "，请尽快领 取您的奖励！";
            mailUtil.sendSampleMail(winningRecordDO.getWinnerEmail(),
                    "中奖通知", context);
        }
    }

    private void sendMessage(List<WinningRecordDO> winningRecordDOS) {
        if(CollectionUtils.isEmpty(winningRecordDOS)){
            logger.info("中奖信息为空，不需要发送信息");
            return;
        }
        for (WinningRecordDO winningRecordDO : winningRecordDOS) {
            Map<String, String> map = new HashMap<>();
            map.put("name", winningRecordDO.getWinnerName());
            map.put("activityName", winningRecordDO.getActivityName());
            map.put("prizeTiers", ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTier()).getMessage());
            map.put("prizeName", winningRecordDO.getPrizeName());
            map.put("winningTime", DateUtil.formatTime(winningRecordDO.getWinningTime()));
            smsUtil.sendMessage("SMS_465985911",
                    winningRecordDO.getWinnerPhoneNumber().getValue(),
                    JacksonUtil.writeValueAsString(map));
        }

    }

    private void statusConvert(DrawPrizeParam param) {
        ConvertActivityStatusDTO convertActivityStatusDTO = new ConvertActivityStatusDTO();
        convertActivityStatusDTO.setActivityId(param.getActivityId());
        convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.COMPLETED);
        convertActivityStatusDTO.setPrizeId(param.getPrizeId());
        convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeEnum.COMPLETED);
        convertActivityStatusDTO.setUserIds(
                param.getWinnerList().stream()
                        .map(DrawPrizeParam.Winner::getUserId)
                        .collect(Collectors.toList())
        );
        convertActivityStatusDTO.setTargetUserStatus(ActivityUserEnum.COMPLETED);
        activityStatusManager.handlerEvent(convertActivityStatusDTO);
    }


}
